package de.akabahn.ebd.fst;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;

import de.akabahn.ebd.comm.Config;

/**
 * Mock extension of the <code>FahrSteuerungAdapter</code> that doesn't require
 * a telnet connection and which sends fix response strings for each command
 * method.
 * 
 */
public class FahrSteuerungSimulation {

	private static final String TEST_HOLD_RESPONSE = "* (HOLD) Halten: Tfz 1234 im Hold-Modus\n> ";
	private static final String TEST_CONT_RESPONSE = "* (CONT) Fortsetzen: Tfz 1234\n> ";
	private static final String TEST_BEF2_RESPONSE = "* (BEF2) Befehl 2: Tfz 1234\n> ";
	private static final String TEST_WAIT_RESPONSE = "* (WAIT) Warten: Tfz 1234\n> ";
	private static final String TEST_ENDW_RESPONSE = "* (ENDW) Abfahren: Tfz 1234\n> ";
	private static final String TEST_UMK_RESPONSE = "* (UMK) Umkehr: Tfz 1234\n> ";
	private static final String TEST_ZN_RESPONSE = "* (ZN) Zugnummer: Tfz 1234 Zn 5678 gespeichert\n> ";
	private static final String TEST_ZN_GET_RESPONSE_101 = "* (ZN) Zugnummer: Tfz 1234 keine Zn \n> ";
	private static final String TEST_ZN_GET_RESPONSE = "* (ZN) Zugnummer: Tfz 101 Zn 5678\n> ";
	private static final String TEST_ADD_MT_RESPONSE = "* (MT) Multitraktion: Tfz 1234 (5678 hinzugefuegt)\n> ";
	private static final String TEST_REMOVE_MT_RESPONSE = "* (MT) Multitraktion: Tfz 1234 (5678 entfernt)\n> ";
	private static final String TEST_SETI_RESPONSE = "* (SETI) Funktion setzen: F0 von Tfz 219 ist jetzt an\n> ";
	private static final String TEST_SETF_RESPONSE = "* (SETF) Funktion setzen: F0 von Tfz 219 ist jetzt aus\n> ";
	private static final String TEST_AUTO_RESPONSE = "* (AUTO) Automatik: Tfz 15 Ort 13G1 in Automatik\n> ";
	private static final String TEST_GO_RESPONSE_OK = "* (GO) Manuelles Fahren: Tfz 15 Fst 5\n> ";
	private static final String TEST_GO_RESPONSE_ERR = "* (GO) Manuelles Fahren: Fehler: Tfz '15' nicht angemeldet\n> ";
	private static final String TEST_RICH_RESPONSE = "* (RICH) Richtung aendern: Tfz 15 Pfeilrichtung\n> ";
	private static final String TEST_STOP_RESPONSE = "* (STOP) Manuelles Fahren: Tfz 15 Fst 0\n> ";
	private static final String TEST_TERM_RESPONSE = "* (TERM) Abmelden: Tfz 15\n> ";
	private static final String TEST_FERTIG_RESPONSE = "* (FERTIG) Fertigmelden: Tfz 15 ist abfahrbereit\n> ";
	private static final String TEST_HNDR_RESPONSE = "* (HNDR) Tfz 15 ist jetzt auf Handregler 7\n> ";
	private static final String TEST_INIT_RESPONSE = "* (INIT) Anmelden: Tfz 15\n> ";
	private static final String TEST_INF_RESPONSE_NOTFZ = ":* (INF) Status: kein Nothalt\n"
			+ "Angemeldete Tfz: 0\n" + "- Kein Tfz angemeldet\n";
	private static final String TEST_INF_RESPONSE_101 = ":* (INF) Status: kein Nothalt\n"
			+ "Angemeldete Tfz: 1\n"
			+ "- Tfz 101: Manuell\n"
			+ "  Fst 30, <= Gegenr, Umk, Ort (keiner)\n"
			+ "                                                 <MT> F0---4 (M:25 Av*:30 Ar*:30)\n> ";
	private static final String TEST_INF_RESPONSE_1010 = ":* (INF) Status: kein Nothalt\n"
			+ "Angemeldete Tfz: 1\n"
			+ "- Tfz 1010: Multitraktion: gesteuert von 101\n"
			+ "  Fst 35, <= Gegenr, Umk, Ort ST0107G3\n"
			+ "  <MULTITRAKTION>                                     F0---4 (M:35 Av*:35 Ar*:35)\n> ";
	private static final String TEST_INF_RESPONSE_1011 = ":* (INF) Status: kein Nothalt\n"
			+ "Angemeldete Tfz: 1\n"
			+ "- Tfz 1011: Multitraktion: gesteuert von 1012\n"
			+ "  Fst 20, Pfeilr =>, Ort 13G2\n"
			+ "  <MULTITRAKTION>                                     F0-2-4 (M:20 Av*:20 Ar*:20)\n> ";
	private static final String TEST_INF_RESPONSE_1012 = ":* (INF) Status: kein Nothalt\n"
			+ "Angemeldete Tfz: 1\n"
			+ "- Tfz 1012: Manuell\n"
			+ "  Fst 20, Pfeilr =>, Ort (keiner)\n"
			+ "                                                 <MT> F0--34 (M:35 Av*:20 Ar*:20)\n> ";
	private static final String TEST_INF_RESPONSE_1452 = ":* (INF) Status: kein Nothalt\n"
			+ "Angemeldete Tfz: 1\n"
			+ "- Tfz 1452: Auf Handregler 7\n"
			+ "  Fst 0, Pfeilr =>, Ort 21G1\n"
			+ "                                                      F0---4 (M:30 Av*:14 Ar*:14)\n> ";
	private static final String TEST_INF_RESPONSE_6282 = ":* (INF) Status: kein Nothalt\n"
			+ "Angemeldete Tfz: 1\n"
			+ "- Tfz 6282: Faehrt\n"
			+ "  Fst 39, Pfeilr =>, Umk, Ort ST1011G1\n"
			+ "  <AUTOM><FAHRB>                                 <MT> F0---4 (M:40 Av*:39 Ar*:39)\n> ";
	private static final String TEST_INF_RESPONSE = ":* (INF) Status: kein Nothalt\n"
			+ "Angemeldete Tfz: 6\n"
			+ "- Tfz 101: Manuell\n"
			+ "  Fst 30, <= Gegenr, Umk, Ort 11G2\n"
			+ "                                                 <MT> F0---4 (M:25 Av*:30 Ar*:30)\n"
			+ "- Tfz 1010: Multitraktion: gesteuert von 101\n"
			+ "  Fst 35, <= Gegenr, Umk, Ort ST0107G3\n"
			+ "  <MULTITRAKTION>                                     F0---4 (M:35 Av*:35 Ar*:35)\n"
			+ "- Tfz 1011: Multitraktion: gesteuert von 1012\n"
			+ "  Fst 20, Pfeilr =>, Ort 13G2\n"
			+ "  <MULTITRAKTION>                                     F0-2-4 (M:20 Av*:20 Ar*:20)\n"
			+ "- Tfz 1012: Manuell\n"
			+ "  Fst 20, Pfeilr =>, Ort (keiner)\n"
			+ "                                                 <MT> F0--34 (M:35 Av*:20 Ar*:20)\n"
			+ "- Tfz 6282: Faehrt\n"
			+ "  Fst 39, Pfeilr =>, Umk, Ort ST1011G1\n"
			+ "  <AUTOM><FAHRB>                                 <MT> F0---4 (M:40 Av*:39 Ar*:39)\n"
			+ "- Tfz 1452: Auf Handregler 7\n"
			+ "  Fst 0, Pfeilr =>, Ort 21G1\n"
			+ "                                                      F0---4 (M:30 Av*:14 Ar*:14)\n> ";

	private ServerSocket serverSocket;
	private boolean terminate;
	
	public static void main(String[] args) {
		try {
			FahrSteuerungSimulation sim = new FahrSteuerungSimulation(Integer.parseInt(args[0]));
			sim.start();
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	
	public FahrSteuerungSimulation(int port) throws IOException {
		serverSocket = new ServerSocket(port);
	}

	public void start() throws IOException {
		do {
			Socket client = serverSocket.accept();
			System.out.println("Client connected: " + client);
			ClientHandler handler = new ClientHandler(client);
			new Thread(handler).start();
		} while (!terminate);

		serverSocket.close();
	}

	private class ClientHandler implements Runnable {
		private Socket client;
		
		public ClientHandler(Socket client) {
			this.client = client;
		}
		
		public void run() {
			PrintWriter out = null;
			BufferedReader bufferedReader = null;
	
			try {
				out = new PrintWriter(client.getOutputStream(), true);
				bufferedReader = new BufferedReader(new InputStreamReader(client.getInputStream()));
				out.print(Config.FST_WELCOME_MSG + Config.FST_EOR_CHARS);
				out.print('\n');
				out.flush();
				System.out.println("Sent welcome message");
				while (true) {
					String command = bufferedReader.readLine();
					System.out.println("Command = " + command);
					if (command != null) {
						String response = sendAndReceive(command);
						out.print(response);
						out.flush();
						System.out.println("Response = " + response);
						if ("SHUTDOWN".equals(response) || "END".equals(response)) {
							client.close();
							if ("SHUTDOWN".equals(response)) {
								System.exit(0);
							}
							break;
						}
					} else {
						break;
					}
				}
			} catch (IOException e) {
				e.printStackTrace();
			} finally {
				if (bufferedReader != null) {
					try {
						bufferedReader.close();
					} catch (IOException e) {
					}
				}
				if (out != null) {
					out.close();
				}
				if (!client.isClosed()) {
					try {
						client.close();
					} catch (IOException e) {
					}
				}
			}
		}
		
		String sendAndReceive(String command) {
			if (command.startsWith("INIT")) {
				return TEST_INIT_RESPONSE;
			} else if (command.startsWith("INF")) {
				if ("INF".equals(command)) {
					return TEST_INF_RESPONSE;
				} else if (command.endsWith("101")) {
					return TEST_INF_RESPONSE_101;
				} else if (command.endsWith("1010")) {
					return TEST_INF_RESPONSE_1010;
				} else if (command.endsWith("1011")) {
					return TEST_INF_RESPONSE_1011;
				} else if (command.endsWith("1012")) {
					return TEST_INF_RESPONSE_1012;
				} else if (command.endsWith("1452")) {
					return TEST_INF_RESPONSE_1452;
				} else if (command.endsWith("6282")) {
					return TEST_INF_RESPONSE_6282;
				} else {
					return TEST_INF_RESPONSE_NOTFZ;
				}
			} else if (command.startsWith("TERM")) {
				return TEST_TERM_RESPONSE;
			} else if (command.startsWith("STOP")) {
				return TEST_STOP_RESPONSE;
			} else if (command.startsWith("RICH")) {
				return TEST_RICH_RESPONSE;
			} else if (command.startsWith("UMK")) {
				return TEST_UMK_RESPONSE;
			} else if (command.startsWith("GO")) {
				if (command.endsWith("25")) {
					return TEST_GO_RESPONSE_ERR;
				} else {
					return TEST_GO_RESPONSE_OK;
				}
			} else if (command.startsWith("AUTO")) {
				return TEST_AUTO_RESPONSE;
			} else if (command.startsWith("SETF")) {
				return TEST_SETF_RESPONSE;
			} else if (command.startsWith("SETI")) {
				return TEST_SETI_RESPONSE;
			} else if (command.startsWith("HOLD")) {
				return TEST_HOLD_RESPONSE;
			} else if (command.startsWith("CONT")) {
				return TEST_CONT_RESPONSE;
			} else if (command.startsWith("BEF2")) {
				return TEST_BEF2_RESPONSE;
			} else if (command.startsWith("WAIT")) {
				return TEST_WAIT_RESPONSE;
			} else if (command.startsWith("ENDW")) {
				return TEST_ENDW_RESPONSE;
			} else if (command.startsWith("ZN")) {
				if (command.split(" ").length == 2) {
					if (command.endsWith("101")) {
						return TEST_ZN_GET_RESPONSE_101;
					} else {
						return TEST_ZN_GET_RESPONSE;
					}
				} else {
					return TEST_ZN_RESPONSE;
				}
			} else if (command.startsWith("MT")) {
				if (command.indexOf('+') != -1) {
					return TEST_ADD_MT_RESPONSE;
				} else {
					return TEST_REMOVE_MT_RESPONSE;
				}
			} else if (command.startsWith("FERTIG")) {
				return TEST_FERTIG_RESPONSE;
			} else if (command.startsWith("HNDR")) {
				return TEST_HNDR_RESPONSE;
			} else if (command.startsWith("END")) {
				return "END";
			} else if (command.startsWith("SHUTDOWN")) {
				return "SHUTDOWN";
			} else {
				return "ERROR\n";
			}
		}
	}
}
